home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / Flight Stability / Flight Stability Source / CFSDirFieldPane.p < prev    next >
Encoding:
Text File  |  1995-07-03  |  8.4 KB  |  313 lines  |  [TEXT/PJMM]

  1. {****************************************************}
  2. {}
  3. {        CFSDirFieldPane.p                                                                                                                                                                                        }
  4. {}
  5. {        Pane methods for the direction field pane.                                                                                                                }
  6. {}
  7. {        Copyright © 1995, Patrick Hew.  All rights reserved.                                                                            }
  8. {}
  9. {****************************************************}
  10.  
  11.  
  12. unit CFSDirFieldPane;
  13.  
  14. interface
  15.  
  16.     uses
  17.         TCL, FSIntf;
  18.  
  19. implementation
  20.  
  21.  
  22.     const
  23.         kPlotSpace = 16;
  24.         kFlightCircRad = kPlotSpace div 4;
  25.  
  26.     const
  27.         kRefreshFreq = 10;
  28.  
  29.  
  30.     { Coordinate conversion functions. }
  31.  
  32.     function PanehFromBank (aBank: Real): Integer;
  33.  
  34.     begin { PanevFromBank }
  35.         PanehFromBank := Trunc(kDirFieldHalfWidth + aBank * kBankToFrame);
  36.     end; { PanevFromBank }
  37.  
  38.     function BankFromPaneh (aPaneh: Integer): Real;
  39.  
  40.     begin { BankFromPaneh }
  41.         BankFromPaneh := (aPaneh - kDirFieldHalfWidth) * kFrameToBank;
  42.     end; { BankFromPaneh }
  43.  
  44.     function PanevFromAOA (aAOA: Real): Integer;
  45.  
  46.     begin { PanehFromAOA }
  47.         PanevFromAOA := Trunc(kDirFieldHalfHeight - aAOA * kAOAToFrame);
  48.     end; { PanehFromAOA }
  49.  
  50.     function AOAFromPanev (aPanev: Integer): Real;
  51.  
  52.     begin { AOAFromPanev }
  53.         AOAFromPanev := -(aPanev - kDirFieldHalfHeight) * kFrameToAOA;
  54.     end; { AOAFromPanev }
  55.  
  56.  
  57. { IFSDirFieldPane }
  58. {}
  59. { Post: Our direction field pane has been initialized. }
  60.  
  61.     procedure CFSDirFieldPane.IFSDirFieldPane (anEnclosure: CView; aSupervisor: CBureaucrat; aWidth, aHeight, aHEncl, aVEncl: integer; aHSizing, aVSizing: SizingOption);
  62.  
  63.     begin { IFSDirFieldPane }
  64.         IPane(anEnclosure, aSupervisor, aWidth, aHeight, aHEncl, aVEncl, aHSizing, aVSizing);
  65.  
  66.         fBankStable := TRUE;
  67.         fAOAStable := TRUE;
  68.  
  69.         oldBank := 0;
  70.         oldAOA := 0;
  71.         currBank := 0;
  72.         currAOA := 0;
  73.  
  74.     end; { IFSDirFieldPane }
  75.  
  76.  
  77. { Draw }
  78. {}
  79. { Post: The part of the direction field given by area has been drawn, }
  80. {        and the current bank and AOA marked in. }
  81.  
  82.     procedure CFSDirFieldPane.Draw (var area: Rect);
  83.  
  84.         var
  85.             yawbankCount, AOACount: Integer; { Don't need LongInt (?) }
  86.             theBankRate, theAOARate: Real;
  87.             plotBankRate, plotAOARate: Integer;
  88.             arrowHor, arrowVer: Integer;
  89.  
  90.             plotBank, plotAOA: Integer;
  91.             flightRect: Rect;
  92.  
  93.     begin { Draw }
  94.         ShowPen;
  95.         PenSize(1, 1);
  96.         PenMode(PatCopy);
  97.  
  98.         { Erase the old flight circle }
  99.  
  100.         plotBank := PanehFromBank(oldBank);
  101.         plotAOA := PanevFromAOA(oldAOA); { Quickdraw coordinates are down positive. }
  102.         SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
  103.  
  104.         PenPat(White);
  105.         FrameOval(flightRect);
  106.  
  107.         { Draw the direction field. }
  108.  
  109.         for yawbankCount := area.left div kPlotSpace - 1 to area.right div kPlotSpace + 1 do begin
  110.             for AOACount := area.top div kPlotSpace - 1 to area.bottom div kPlotSpace + 1 do begin
  111.                 { Note that drawing is done with +ve right, down }
  112.                 { whereas we are drawing a graph with +ve right, up. }
  113.  
  114.                 GetDirection(BankFromPaneh(yawbankCount * kPlotSpace), AOAFromPanev(AOACount * kPlotSpace), theBankRate, theAOARate);
  115.  
  116.                 { Tweak the arrows so that they fit. }
  117.                 { Arrows are only to scale up to kPlotSpace. }
  118.  
  119.                 plotBankRate := Trunc(theBankRate * kBankToFrame) div 4;
  120.                 plotAOARate := Trunc(theAOARate * kAOAToFrame) div 4;
  121.  
  122.                 if plotBankRate > kPlotSpace then begin
  123.                     plotBankRate := kPlotSpace;
  124.                 end { if }
  125.                 else if plotBankRate < -kPlotSpace then begin
  126.                     plotBankRate := -kPlotSpace;
  127.                 end; { else }
  128.  
  129.                 if plotAOARate > kPlotSpace then begin
  130.                     plotAOARate := kPlotSpace;
  131.                 end { if }
  132.                 else if plotAOARate < -kPlotSpace then begin
  133.                     plotAOARate := -kPlotSpace;
  134.                 end; { else }
  135.  
  136.                 PenPat(Black);
  137.                 MoveTo(yawbankCount * kPlotSpace - plotBankRate div 2, AOACount * kPlotSpace + plotAOARate div 2);
  138.                 Line(plotBankRate, -plotAOARate);
  139.  
  140.                 if (plotBankRate <> 0) and (plotAOARate <> 0) then begin
  141.                     Line(-2 * plotBankRate div Abs(plotBankRate), 0);
  142.                     Move(2 * plotBankRate div Abs(plotBankRate), 0);
  143.                     Line(0, 2 * plotAOARate div Abs(plotAOARate)); { Note reverse direction }
  144.                 end { if }
  145.                 else if (plotBankRate <> 0) and (plotAOARate = 0) then begin
  146.                     Line(-plotBankRate div Abs(plotBankRate), 1);
  147.                     Line(0, -2);
  148.                 end { else if }
  149.                 else if (plotBankRate = 0) and (plotAOARate <> 0) then begin
  150.                     Line(1, plotAOARate div Abs(plotAOARate)); { Note reverse direction }
  151.                     Line(-2, 0);
  152.                 end; { else if }
  153.  
  154.             end; { for }
  155.         end; { for }
  156.  
  157.         { Draw the new flight circle. }
  158.  
  159.         plotBank := PanehFromBank(currBank);
  160.         plotAOA := PanevFromAOA(currAOA); { Quickdraw coordinates are down positive. }
  161.         SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
  162.  
  163.         FrameOval(flightRect);
  164.  
  165.     end; { Draw }
  166.  
  167.  
  168. { SetBankStability }
  169. {}
  170. { Post: The bank axes have been set to the given stability, }
  171. {        and the plane prepared for redrawing. }
  172.  
  173.     procedure CFSDirFieldPane.SetBankStability (fStable: Boolean);
  174.  
  175.     begin { SetStability }
  176.         fBankStable := fStable;
  177.  
  178.         Refresh;
  179.     end; { SetBankStability }
  180.  
  181.  
  182. { SetAOAStability }
  183. {}
  184. { Post: The AOA axes have been set to the given stability, }
  185. {        and the plane prepared for redrawing. }
  186.  
  187.     procedure CFSDirFieldPane.SetAOAStability (fStable: Boolean);
  188.  
  189.     begin { SetStability }
  190.         fAOAStable := fStable;
  191.  
  192.         Refresh;
  193.     end; { SetAOAStability }
  194.  
  195.  
  196. { GetDirection }
  197. {}
  198. { Post: The bank and AOA rates have been obtained for the }
  199. {        required point in the direction field. }
  200. { Note: This function is hard coded as a method for the direction }
  201. {        field pane, although in principle of course we can store it as a }
  202. {        method in a dedicated object. It just wasn't worth the effort. }
  203.  
  204.     procedure CFSDirFieldPane.GetDirection (aBank, aAOA: Real; var aBankRate, aAOARate: Real);
  205.  
  206.     begin { GetDirection }
  207.         { Bank }
  208.         if fBankStable then begin
  209.             aBankRate := -aBank;
  210.         end { if }
  211.         else begin
  212.             aBankRate := Sin(aBank * 2);
  213.         end; { else }
  214.  
  215.         { AOA }
  216.         if fAOAStable then begin
  217.             aAOARate := -2 * aAOA;
  218.         end { if }
  219.         else begin
  220.             { Set up the direction field to limit the AOA so that }
  221.             { it cannot exceed ± pi/2, and is hard pushed to }
  222.             { exceed ± pi/4. }
  223.             { Recall that the  maximum AOA change which the }
  224.             { stick can exert (per frame) is pi/12. We set it }
  225.             { up so that this rate is met (or exceeded) by ± pi/3. }
  226.  
  227.             if aAOA < -pi / 4 then begin
  228.                 aAOARate := -(aAOA + pi / 4) * kRefreshFreq;
  229.             end { if }
  230.             else if aAOA > pi / 4 then begin
  231.                 aAOARate := -(aAOA - pi / 4) * kRefreshFreq;
  232.             end
  233.             else begin
  234.                 aAOARate := Sin(aAOA * 4);
  235.             end; { else }
  236.         end; { else }
  237.  
  238.     end; { GetDirection }
  239.  
  240.  
  241. { GetCurrPosition }
  242. {}
  243. { Post: The current bank and AOA values have been obtained. }
  244.  
  245.     procedure CFSDirFieldPane.GetCurrPosition (var aCurrBank, aCurrAOA: Real);
  246.  
  247.     begin { GetCurrPosition }
  248.         aCurrBank := currBank;
  249.         aCurrAOA := currAOA;
  250.     end; { GetCurrPosition }
  251.  
  252.  
  253. { SetCurrPosition }
  254. {}
  255. { Post: The current bank and AOA values have been set. }
  256. { Note: This is used in "autopilot" mode to ensure that we fly straight and level. }
  257.  
  258.     procedure CFSDirFieldPane.SetCurrPosition (aCurrBank, aCurrAOA: Real);
  259.  
  260.         var
  261.             plotBank, plotAOA: Integer;
  262.             flightRect: Rect;
  263.  
  264.     begin { SetCurrPosition }
  265.         oldBank := currBank;
  266.         oldAOA := currAOA;
  267.         currBank := aCurrBank;
  268.         currAOA := aCurrAOA;
  269.  
  270.         plotBank := PanehFromBank(oldBank);
  271.         plotAOA := PanevFromAOA(oldAOA);
  272.         SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
  273.         RefreshRect(flightRect);
  274.  
  275.         plotBank := PanehFromBank(currBank);
  276.         plotAOA := PanevFromAOA(currAOA);
  277.         SetRect(flightRect, plotBank - kFlightCircRad, plotAOA - kFlightCircRad, plotBank + kFlightCircRad, plotAOA + kFlightCircRad);
  278.         RefreshRect(flightRect);
  279.  
  280.     end; { SetCurrPosition }
  281.  
  282.  
  283. { UpdatePosition }
  284. {}
  285. { Post: The current position in the direction field has been updated, }
  286. {        including the external input. }
  287.  
  288.     procedure CFSDirFieldPane.UpdatePosition (aBankChange, aAOAChange: Real);
  289.  
  290.         var
  291.             theBankRate, theAOARate: Real;
  292.             theNewBank, theNewAOA: Real;
  293.  
  294.     begin { UpdatePosition }
  295.         GetDirection(currBank, currAOA, theBankRate, theAOARate);
  296.  
  297.         { We have rotational degeneracy in the case of bank. }
  298.         theNewBank := currBank + aBankChange + theBankRate / kRefreshFreq;
  299.  
  300.         if (currBank < pi) and (theNewBank > pi) then begin
  301.             theNewBank := theNewBank - 2 * pi;
  302.         end { if }
  303.         else if (currBank > -pi) and (theNewBank < -pi) then begin
  304.             theNewBank := theNewBank + 2 * pi;
  305.         end; { else }
  306.  
  307.         theNewAOA := currAOA + aAOAChange + theAOARate / kRefreshFreq;
  308.  
  309.         SetCurrPosition(theNewBank, theNewAOA);
  310.     end; { UpdatePosition }
  311.  
  312.  
  313. end. { CFSDirFieldPane }